using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ExtendedMvc.Common.Diagnostics;
using ExtendedMvc.Html;

namespace ExtendedMvc.Elements {
	public class RadioButtonSet<TModel> : RadioButtonSetBase<RadioButtonSet<TModel>, TModel> where TModel : class {
		public RadioButtonSet(IModelViewHelper<TModel> helper, string memberName, string id = null) : base(helper, memberName, id) { }
	}

	public abstract class RadioButtonSetBase<T, TModel> : Selection<T, TModel>
		where T : RadioButtonSetBase<T, TModel>
		where TModel : class {
		private const string optionsSuffix = "_Options";

		private int _columns;
		private ListDirection _direction;

		protected RadioButtonSetBase(IModelViewHelper<TModel> helper, string memberName, string id = null) : base(helper, HtmlTag.Div, memberName, (id ?? memberName + optionsSuffix), false) {
			SetAttribute(HtmlAttribute.Type, "optionList");
			_columns = 0;
			_direction = ListDirection.Horizontally;
		}

		public virtual T Direction(ListDirection value) {
			_direction = value;
			return (T)this;
		}

		public virtual T Columns(int value) {
			Check.Argument.IsNotNegative(value, "value");
			_columns = value;
			return (T)this;
		}

		protected override bool UseNameAttribute { get { return false; } }

		protected override void Prepare() {
			Styles(display => "inline-block");
			//label.Styles(vertical_align => "middle");
			base.Prepare();
		}

		private void AddOption(StringBuilder sb, KeyValuePair<object, string> option) {
			var radioButton = new RadioButtonOption<TModel>(helper, memberName, option.Key, IsSelected(option.Key));
			radioButton.Id(string.Format("{0}_{1}", memberName, option.Key));
			radioButton.AddLabel(option.Value);
			sb.Append(radioButton);
		}

		protected override string RenderOptions() {
			if (options == null) throw new ArgumentException("The control must have at least one option defined.", "Options");
			var sb = new StringBuilder();
			var count = options.Count;
			if (_direction == ListDirection.Horizontally) {
				var rows = _columns == 0 ? 1 : (int)(((count - 1) / _columns) + 1);
				var cols = _columns == 0 ? count : _columns;
				for (var r = 0; r < rows; r++) {
					sb.Append("<div>");
					for (var c = 0; c < cols; c++) {
						AddOption(sb, options.ElementAt((r * cols) + c));
					}
					sb.Append("</div>");
				}
			} else {
				var rows = _columns == 0 ? count : (int)(((count - 1) / _columns) + 1);
				var cols = _columns == 0 ? 1 : _columns;
				for (var r = 0; r < rows; r++) {
					sb.Append("<div>");
					for (var c = 0; c < cols; c++) {
						AddOption(sb, options.ElementAt((c * rows) + r));
					}
					sb.Append("</div>");
				}
			}
			return sb.ToString();
		}
	}
}